﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description: SqlScriptViewModel
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using VmroleAuthor.Models;

namespace VmroleAuthor.ViewModels
{
    public class SqlScriptViewModel : TreeViewItemViewModel, IDataErrorInfo, IProduceValidationResults, ICanBeRemovedFromTree
    {
        private readonly SQLScriptCommand sqlScriptCommand;
        private readonly VmRoleResourceExtensionViewModel vmRoleResourceExtensionViewModel;

        private StringParameterizableProperty databaseName;
        private IntParameterizableProperty deploymentOrder;
        private StringParameterizableProperty commandParameters;
        private BoolParameterizableProperty encryptConnection;
        private IntParameterizableProperty executionTimeoutSeconds;
        private IntParameterizableProperty loginTimeoutSeconds;
        private StringParameterizableProperty outputFilePath;
        private EnumParameterizableProperty sqlAuthenticationType;
        private CredentialParameterizableProperty scriptCredential;
        private EnumParameterizableProperty scriptType;

        private ReferencedApplicationPayloadViewModel sqlScriptPackage;

        public static class PropertyNames
        {
            public const string Summary = "Summary";
            public const string SqlScriptPackage = "SqlScriptPackage";
            public const string DatabaseName = "DatabaseName";
            public const string DeploymentOrder = "DeploymentOrder";
            public const string CommandParameters = "CommandParameters";
            public const string EncryptConnection = "EncryptConnection";
            public const string ExecutionTimeoutSeconds = "ExecutionTimeoutSeconds";
            public const string LoginTimeoutSeconds = "LoginTimeoutSeconds";
            public const string OutputFilePath = "OutputFilePath";
            public const string SQLAuthenticationType = "SQLAuthenticationType";
            public const string ScriptCredential = "ScriptCredential";
            public const string ScriptType = "ScriptType";
        }

        public SqlScriptViewModel(
            SQLScriptCommand sqlScriptCommand,
            TreeViewItemViewModel parentItemViewModel,
            VmRoleResourceExtensionViewModel resourceExtensionViewModel)
            : base(parentItemViewModel, true)
        {
            this.sqlScriptCommand = sqlScriptCommand;
            this.vmRoleResourceExtensionViewModel = resourceExtensionViewModel;
            this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();
        }

        public string Summary
        {
            get
            {                
                return "SQL Script";
            }
        }

        public SQLScriptCommand SQLScriptCommand
        {
            get { return this.sqlScriptCommand; }
        }

        public ReferencedApplicationPayloadViewModel SqlScriptPackage
        {
            get
            {
                if (this.sqlScriptPackage == null)
                {
                    Func<string> getter = () => this.sqlScriptCommand.SQLScriptApplicationPayloadId;
                    Action<string> setter = delegate(string value) { this.sqlScriptCommand.SQLScriptApplicationPayloadId = value; };
                    this.sqlScriptPackage = new ReferencedApplicationPayloadViewModel(this.vmRoleResourceExtensionViewModel, ValidationHelper.PayloadType.SqlScript, getter, setter, true, PropertyNames.SqlScriptPackage);
                }
                return this.sqlScriptPackage;
            }
        }

        public StringParameterizableProperty DatabaseName
        {
            get
            {
                if (this.databaseName == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.DatabaseName;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.DatabaseName = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.DatabaseName;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Database name"
                    };

                    this.databaseName = new StringParameterizableProperty(
                        PropertyNames.DatabaseName,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL script command Database name",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.databaseName;
            }
        }

        /// <summary>
        /// int
        /// </summary>      
        public IntParameterizableProperty DeploymentOrder
        {
            get
            {
                if (this.deploymentOrder == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.DeploymentOrder;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.DeploymentOrder = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.DeploymentOrder;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultInitialValue = "1",
                        DefaultEnglishLabelText = "SQL script deployment order"
                    };

                    this.deploymentOrder = new IntParameterizableProperty(
                        PropertyNames.DeploymentOrder,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "SQL script command Deployment Order",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo); //int
                }
                return this.deploymentOrder;
            }
        }

        public StringParameterizableProperty CommandParameters
        {
            get
            {
                if (this.commandParameters == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.CommandParameters;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.CommandParameters = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.CommandParameters;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Command parameters"
                    };


                    this.commandParameters = new StringParameterizableProperty(
                        PropertyNames.CommandParameters,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL script command parameters",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.commandParameters;
            }
        }

        public BoolParameterizableProperty EncryptConnection
        {
            get
            {
                if (this.encryptConnection == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.EncryptConnection;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.EncryptConnection = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.EncryptConnection;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultEnglishLabelText = "Encrypt connection",
                        DefaultInitialValue = "false"
                    };

                    this.encryptConnection = new BoolParameterizableProperty(
                        PropertyNames.EncryptConnection,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "SQL script command encrypt connection",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo
                     );
                }
                return this.encryptConnection;
            }
        }

        public IntParameterizableProperty ExecutionTimeoutSeconds
        {
            get
            {
                if (this.executionTimeoutSeconds == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.ExecutionTimeoutSeconds;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.ExecutionTimeoutSeconds = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ExecutionTimeoutSeconds;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultEnglishLabelText = "Execution timeout in seconds",
                        DefaultInitialValue = int.MaxValue.ToString(CultureInfo.InvariantCulture)
                    };

                    this.executionTimeoutSeconds = new IntParameterizableProperty(
                        PropertyNames.ExecutionTimeoutSeconds,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "SQL script command execution timeout in seconds",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.executionTimeoutSeconds;
            }
        }

        public IntParameterizableProperty LoginTimeoutSeconds
        {
            get
            {
                if (this.loginTimeoutSeconds == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.LoginTimeoutSeconds;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.LoginTimeoutSeconds = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.LoginTimeoutSeconds;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultEnglishLabelText = "Login timeout in seconds",
                        DefaultInitialValue = int.MaxValue.ToString(CultureInfo.InvariantCulture)
                    };

                    this.loginTimeoutSeconds = new IntParameterizableProperty(
                        PropertyNames.LoginTimeoutSeconds,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "SQL script command login timeout in seconds",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.loginTimeoutSeconds;
            }
        }


        public StringParameterizableProperty OutputFilePath
        {
            get
            {
                if (this.outputFilePath== null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.OutputFilePath;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.OutputFilePath = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.OutputFilePath;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Output file path"
                    };

                    this.outputFilePath = new StringParameterizableProperty(
                        PropertyNames.OutputFilePath,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL script command Output file path",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.outputFilePath;
            }
        }

        /// <summary>
        /// SQLAuthenticationType
        /// </summary>
        public EnumParameterizableProperty SQLAuthenticationType
        {
            get
            {
                if (this.sqlAuthenticationType == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.SQLAuthenticationType;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.SQLAuthenticationType = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.SQLAuthenticationType;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Option,
                        DefaultEnglishLabelText = "SQL authentication type",
                        Options = new List<string>(Enum.GetNames(typeof(SQLAuthenticationType)))
                    };


                    this.sqlAuthenticationType = new EnumParameterizableProperty(
                        PropertyNames.SQLAuthenticationType,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL authentication type",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        typeof(SQLAuthenticationType),
                        false,
                        viewDefParamInfo);
                }
                return this.sqlAuthenticationType;
            }
        }


        public CredentialParameterizableProperty ScriptCredential
        {
            get
            {
                if (this.scriptCredential == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.ScriptCredential;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.ScriptCredential = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ScriptCredential;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Credential,
                        DefaultEnglishLabelText = "SQL script credential"
                    };

                    this.scriptCredential = new CredentialParameterizableProperty(
                        PropertyNames.ScriptCredential,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Credential,
                        "SQL script command script credential",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.scriptCredential;
            }
        }


        /// <summary>
        /// SQLScriptType 
        /// </summary>            
        public EnumParameterizableProperty ScriptType
        {
            get
            {
                if (this.scriptType == null)
                {
                    Func<string> paramValueGetter = () => this.sqlScriptCommand.ScriptType;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlScriptCommand.ScriptType = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ScriptType;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Option,
                        DefaultEnglishLabelText = "SQL script command type",
                        Options = new List<string>(Enum.GetNames(typeof(SQLScriptType)))
                    };

                    this.scriptType = new EnumParameterizableProperty(
                        PropertyNames.ScriptType,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL script command script type",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        typeof(SQLScriptType),
                        true,
                        viewDefParamInfo);
                }
                return this.scriptType;
            }
        }

        protected override void LoadChildren()
        {
            // No children                          
        }

        public void Cleanup()
        {
            this.IsExpanded = true;
            ParametersAndPayloadCleanupHelper.CleanupParametersAndPayload(this, typeof(PropertyNames));
        }

        public ObservableCollection<CloudServiceModelValidationResult> ValidationResults { get; private set; }

        public void UpdateValidationResults()
        {
            ModelValidationResultsHelper.UpdateValidationResults(this, typeof(PropertyNames));
            //Add any other cross-field validations error           
        }

        public string this[string columnName]
        {
            get { return null; }
        }

        public string Error { get; set; }
    }
}
